package com.lft.examsys.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.lft.examsys.entity.CreditUser;
import com.lft.examsys.mapper.UserMapper;
import com.lft.examsys.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    private ObjectMapper mapper = new ObjectMapper();

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private UserMapper userMapper;


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/**/*.css", "/**/*.js", "/**/*.jpg", "/**/*.png");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        mapper.registerModule(new JavaTimeModule());
        http.exceptionHandling().accessDeniedPage("/");
        http.
                formLogin()
                .loginPage("/")
                .loginProcessingUrl("/login")
                .successHandler((request, response, authentication) -> {
                    response.sendRedirect("/");
                }).
                failureHandler((request, response, exception) -> {
                    String username = request.getParameter("username");
                    request.setAttribute("username", username);
                    request.setAttribute("loginShowed", "loginShowed");
                    request.getRequestDispatcher("/index.jsp").forward(request, response);
                }).


                and().
                logout().
                logoutUrl("/logout").
                logoutSuccessHandler((request, response, authentication) -> {
                    response.sendRedirect("/");
                }).

                and().
                authorizeRequests().
//                anyRequest().permitAll().
                antMatchers("/", "/login", "/kaptcha", "/codeCheck", "/register").permitAll().
                anyRequest().authenticated().

                and().
                csrf().disable();

        http.addFilterAt(new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain) throws ServletException, IOException {

                HttpServletRequest request = (HttpServletRequest) req;
                if ((request.getRequestURI().equals("/login") || request.getRequestURI().equals("/register")) && request.getMethod().equals("POST")) {
                    HttpServletResponse response = (HttpServletResponse) resp;
                    String username = req.getParameter("username");
                    String password = req.getParameter("password");
                    String verify = req.getParameter("verify");
                    Object code = request.getSession().getAttribute("code");
                    if (code == null || !code.toString().equalsIgnoreCase(verify)) {
                        request.setAttribute("errMsg", "验证码错误");
                        request.setAttribute("password", password);
                        request.setAttribute("username", username);
                        request.setAttribute("loginShowed", "loginShowed");
                        request.getRequestDispatcher("/index.jsp").forward(request, response);
                        return;
                    }
                }


                SecurityContext context = SecurityContextHolder.getContext();
                Authentication authentication = context.getAuthentication();
                CreditUser user = null;
                if (authentication != null)
                    user = authentication.getPrincipal().equals("anonymousUser") ? null : (CreditUser) authentication.getPrincipal();

                if (user != null) {
                    user.UpdateUser(userMapper.findByUsername(user.getUsername()));
                    if (!user.isAccountNonLocked()) {
                        resp.sendRedirect("/logout");
                        return;
                    }
                    List<String> permissions = null;
                    if (user.getUsername().equalsIgnoreCase("root")) {
                        permissions = permissionService.getAllPermissionName();
                    } else {
                        if (user.getRoleId() == null) {
                            permissions = permissionService.getActivePermissionIdByRoleId("default");
                        } else {
                            permissions = permissionService.getActivePermissionIdByRoleId(user.getRoleId());
                        }
                    }
                    user.fillAuthorize(permissions);
                    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                            user, authentication.getCredentials(),
                            user.getAuthorities());
                    token.setDetails(authentication.getDetails());
                    context.setAuthentication(token);
                }
                filterChain.doFilter(req, resp);
            }
        }, UsernamePasswordAuthenticationFilter.class);

    }
}
